﻿using Common.Infrastructure.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace Common.Infrastructure
{
    public static class LibSysUtils
    {
        private static readonly string[] DB_KEYWORDS = new string[] { "ORDER", "DESC", "TEXT", "GROUP", "ASC", "MIN", "MAX", "SUM", "DATE", "DATA", "DEC", "CASE", "CAST" };

        private static string[] staticNoCopyFields = new string[] { "id", "row_version", "modify_time", "create_time" };

        /// <summary>
        /// 复制对象.
        /// </summary>
        /// <param name="target">目标对象.</param>
        /// <param name="source">源对象.</param>
        /// <param name="noCopyFields">无复制的字段列表.</param>
        public static void CopyObject(object target, object source, params string[] noCopyFields)
        {
            if (target == null || source == null)
            {
                return;
            }

            var targetType = target.GetType();
            var srcType = source.GetType();

            foreach (var p in srcType.GetProperties())
            {
                if (staticNoCopyFields != null && staticNoCopyFields.Any(t => string.Compare(p.Name, t, true) == 0))
                {
                    continue;
                }

                if (noCopyFields != null && noCopyFields.Any(t => string.Compare(p.Name, t, true) == 0))
                {
                    continue;
                }

                var targetP = targetType.GetProperty(p.Name);
                if (targetP != null && p.PropertyType == targetP.PropertyType)
                {
                    var value = p.GetValue(source, null);
                    try
                    {
                        targetP.SetValue(target, value);
                    }
                    catch
                    {
                    }
                }
            }
        }

        /// <summary>
        /// 对象转字符串.
        /// </summary>
        /// <param name="obj">对象.</param>
        /// <returns>字符串.</returns>
        public static string ToString(object obj)
        {
            if (obj == null)
            {
                return null;
            }

            try
            {
                return obj.ToString();
            }
            catch
            {
                return null;
            }
        }

        /// <summary>
        /// 对象转Int值.
        /// </summary>
        /// <param name="obj">对象.</param>
        /// <returns>int值.</returns>
        public static int ToInt(object obj)
        {
            if (obj == null || string.IsNullOrEmpty(obj.ToString()))
            {
                return 0;
            }

            try
            {
                return Convert.ToInt32(obj);
            }
            catch
            {
            }

            return 0;
        }

        /// <summary>
        /// 对象转bool值.
        /// </summary>
        /// <param name="obj">对象.</param>
        /// <returns>bool值.</returns>
        public static bool ToBoolean(object obj)
        {
            if (obj == null || string.IsNullOrEmpty(obj.ToString()))
            {
                return false;
            }

            try
            {
                return Convert.ToBoolean(obj);
            }
            catch
            {
            }

            return false;
        }

        /// <summary>
        /// 对象转Decimal值.
        /// </summary>
        /// <param name="obj">对象.</param>
        /// <returns>Decimal值.</returns>
        public static decimal ToDecimal(object obj)
        {
            if (obj == null || string.IsNullOrEmpty(obj.ToString()))
            {
                return 0;
            }

            try
            {
                return Convert.ToDecimal(obj);
            }
            catch
            {
            }

            return 0;
        }

        /// <summary>
        /// 对象转DateTime值.
        /// </summary>
        /// <param name="obj">对象.</param>
        /// <returns>DateTime值.</returns>
        public static DateTime? ToDateTime(object obj)
        {
            if (obj == null || string.IsNullOrEmpty(obj.ToString()))
            {
                return null;
            }

            try
            {
                return Convert.ToDateTime(obj);
            }
            catch
            {
            }

            return null;
        }

        /// <summary>
        /// 格式化小数点.
        /// </summary>
        /// <param name="qty">数.</param>
        /// <param name="len">小数点位数.</param>
        /// <param name="type">进位方式.</param>
        /// <returns>格式化后的数.</returns>
        public static decimal Round(decimal qty, int len, LibRoundTypeEnum type)
        {
            switch (type)
            {
                case LibRoundTypeEnum.向上进位:
                    if (len != 0)
                    {
                        string[] array2 = qty.ToString().Split('.');
                        if (array2.Length >= 2)
                        {
                            string text2 = array2[1].PadRight(6, '0');
                            qty = Convert.ToDecimal(array2[0] + "." + text2.Substring(0, len));
                        }
                    }
                    else
                    {
                        qty = Math.Ceiling(qty);
                    }

                    return qty;
                case LibRoundTypeEnum.向下舍弃:
                    if (len != 0)
                    {
                        string[] array = qty.ToString().Split('.');
                        if (array.Length >= 2)
                        {
                            string text = array[1].PadRight(6, '0');
                            qty = Convert.ToDecimal(array[0] + "." + text.Substring(0, len));
                            if (text[len] != '0')
                            {
                                qty += 1m / (decimal)Math.Pow(10.0, len);
                            }
                        }
                    }
                    else
                    {
                        qty = Math.Floor(qty);
                    }

                    return qty;
                default:
                    return Math.Round(qty, len, MidpointRounding.AwayFromZero);
            }
        }

        /// <summary>
        /// 获取GRpc序列化字符串.
        /// </summary>
        /// <param name="v">原始字符串.</param>
        /// <returns>转换后字符串.</returns>
        public static string GrpcSerial(string v)
        {
            if (v == null)
            {
                return string.Empty;
            }

            return v;
        }

        /// <summary>
        /// 获取GRpc反序列化字符串.
        /// </summary>
        /// <param name="v">原始字符串.</param>
        /// <returns>转换后字符串.</returns>
        public static string GrpcDeSerial(string v)
        {
            if (string.IsNullOrEmpty(v))
            {
                return null;
            }

            return v;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="word"></param>
        /// <param name="toUpper"></param>
        /// <returns></returns>
        public static string Hash_MD5_32(string word, bool toUpper = true)
        {
            var md5csp = System.Security.Cryptography.MD5.Create();
            try
            {
                byte[] bytValue = System.Text.Encoding.UTF8.GetBytes(word);
                byte[] bytHash = md5csp.ComputeHash(bytValue);
                md5csp.Clear();

                ////根据计算得到的Hash码翻译为MD5码
                string hashStr = string.Empty;
                for (int counter = 0; counter < bytHash.Length; counter++)
                {
                    long i = bytHash[counter] / 16;
                    string tempStr;
                    if (i > 9)
                    {
                        tempStr = ((char)(i - 10 + 0x41)).ToString();
                    }
                    else
                    {
                        tempStr = ((char)(i + 0x30)).ToString();
                    }

                    i = bytHash[counter] % 16;
                    if (i > 9)
                    {
                        tempStr += ((char)(i - 10 + 0x41)).ToString();
                    }
                    else
                    {
                        tempStr += ((char)(i + 0x30)).ToString();
                    }

                    hashStr += tempStr;
                }

                ////根据大小写规则决定返回的字符串
                return toUpper ? hashStr : hashStr.ToLower();
            }
            finally
            {
                md5csp.Dispose();
            }
        }

        public static void GetSqlByEntity(DataBaseTypeEnum dataBaseType, object obj, List<string> sqlLists, string dstOrgId, int sqlType)
        {
            if (obj == null || sqlLists == null)
            {
                return;
            }

            Type objType = obj.GetType();
            Dictionary<string, string> fields = new Dictionary<string, string>();
            foreach (var mi in objType.GetProperties())
            {
                if (mi.Name.StartsWith("nav_", StringComparison.OrdinalIgnoreCase) ||
                    mi.Name.StartsWith("vir_", StringComparison.OrdinalIgnoreCase) ||
                    mi.Name.ToLower() != mi.Name)
                {
                    continue;
                }

                string fieldName = mi.Name;
                string value = string.Empty;
                if (string.Compare(mi.Name, "org_id", true) == 0)
                {
                    if (string.IsNullOrEmpty(dstOrgId))
                    {
                        var tmpObj = mi.GetValue(obj, null);
                        if (tmpObj != null)
                        {
                            value = tmpObj.ToString();
                        }
                    }
                    else
                    {
                        value = dstOrgId;
                    }
                }
                else
                {
                    string propertyTypeName = mi.PropertyType.Name;
                    string fullTypeName = mi.PropertyType.FullName;
                    if (string.Compare(propertyTypeName, "DateTime", true) == 0 || fullTypeName.IndexOf("DateTime", StringComparison.OrdinalIgnoreCase) > -1)
                    {
                        var tmpObj = mi.GetValue(obj, null);
                        if (tmpObj != null)
                        {
                            if (dataBaseType == DataBaseTypeEnum.Oracle)
                            {
                                value = "to_date('" + ((DateTime)tmpObj).ToString("yyyy/MM/dd hh:mm:ss") + "','yyyy-mm-dd hh24-mi-ss')";
                            }
                            else if (dataBaseType == DataBaseTypeEnum.PostgreSQL)
                            {
                                value = ((DateTime)tmpObj).ToString("yyyy-MM-dd HH:mm:ss");
                            }
                            else
                            {
                                value = tmpObj.ToString();
                            }
                        }
                    }
                    else if (string.Compare(propertyTypeName, "bool", true) == 0 || string.Compare(propertyTypeName, "boolean", true) == 0 || fullTypeName.IndexOf("bool", StringComparison.OrdinalIgnoreCase) > -1)
                    {
                        var tmpObj = mi.GetValue(obj, null);
                        if (tmpObj != null)
                        {
                            value = ((bool)tmpObj) ? "1" : "0";
                        }
                    }
                    else
                    {
                        var tmpObj = mi.GetValue(obj, null);
                        if (tmpObj != null)
                        {
                            value = tmpObj.ToString();
                        }
                    }

                    if (string.IsNullOrEmpty(value))
                    {
                        value = "NULL";
                    }
                }

                if (!string.IsNullOrEmpty(value))
                {
                    fields[fieldName] = value;
                }
            }

            if (fields.Count > 0)
            {
                string tableName = objType.Name;
                if (string.Compare(objType.Namespace, "System.Data.Entity.DynamicProxies", true) == 0 ||
                     string.Compare(objType.Namespace, "Castle.Proxies", true) == 0)
                {
                    tableName = objType.BaseType.Name;
                }

                Regex valueRegex = new Regex("^\\w\\S*[\u4E00-\u9FA5]\\w\\S*$");
                StringBuilder builderUp = new StringBuilder();
                StringBuilder builderupField = new StringBuilder();
                StringBuilder builderinsert = new StringBuilder();
                builderUp.Append("UPDATE " + tableName + " SET ");
                builderinsert.Append("INSERT INTO " + tableName + "(");
                foreach (var item in fields)
                {
                    string field = item.Key;
                    ////关键字加引号
                    if (DB_KEYWORDS.Any(t => string.Compare(t, field, true) == 0)) 
                    {
                        field = (dataBaseType == DataBaseTypeEnum.MySql ? "`" : "\"") + field + (dataBaseType == DataBaseTypeEnum.MySql ? "`" : "\"");
                    }

                    builderinsert.Append(field);
                    builderinsert.Append(",");
                }

                builderinsert.Length--;
                builderinsert.Append(") VALUES(");
                string id = string.Empty;
                foreach (var item in fields)
                {
                    string field = item.Key;
                    string value = item.Value;
                    if (string.Compare(value, "NULL") != 0 && value.IndexOf("to_date", StringComparison.OrdinalIgnoreCase) == -1)
                    {
                        value = (valueRegex.IsMatch(value) ? "N" : string.Empty) + "'" + value + "'";
                    }

                    ////关键字加引号
                    if (DB_KEYWORDS.Any(t => string.Compare(t, field, true) == 0))
                    {
                        field = (dataBaseType == DataBaseTypeEnum.MySql ? "`" : "\"") + field + (dataBaseType == DataBaseTypeEnum.MySql ? "`" : "\"");
                    }

                    if (string.Compare(field, "id", true) == 0)
                    {
                        id = value;
                    }
                    else
                    {
                        builderUp.Append(field + "=" + value + ",");
                        builderupField.Append(field + "=" + value + ",");
                    }

                    builderinsert.Append(value + ",");
                }

                builderUp.Length--;
                builderinsert.Length--;
                builderupField.Length--;

                builderinsert.Append(")");
                builderUp.Append(" WHERE id=" + id);

                if (sqlType == 2)
                {
                    sqlLists.Add(builderUp.ToString() + ";");
                }
                else if (sqlType == 1)
                {
                    sqlLists.Add(builderinsert.ToString() + ";");
                }
                else if (dataBaseType == DataBaseTypeEnum.Oracle)
                {
                    sqlLists.Add(string.Format(" {0} ; if sql % notfound then {1} ; end if; ", builderUp.ToString(), builderinsert.ToString()));
                }
                else if (dataBaseType == DataBaseTypeEnum.MySql)
                {
                    sqlLists.Add(string.Format(" {0}  ON DUPLICATE KEY UPDATE {1}; ", builderinsert.ToString(), builderupField.ToString()));
                }
                else if (dataBaseType == DataBaseTypeEnum.PostgreSQL)
                {
                    sqlLists.Add(string.Format(@" do language plpgsql $$ declare v_rowCount int:= 0; begin {0}; GET DIAGNOSTICS v_rowCount = ROW_COUNT; if (v_rowCount = 0) then {1}; end if; end $$;", builderUp.ToString(), builderinsert.ToString()));
                }
                else
                {
                    sqlLists.Add(string.Format("begin {0}; if @@RowCount = 0 begin {1} ; end  end ", builderUp.ToString(), builderinsert.ToString()));
                }
            }
        }

        public static string Html2Text(string htmlStr)
        {
            if (string.IsNullOrEmpty(htmlStr))
            {
                return string.Empty;
            }

            string regEx_style = "<style[^>]*?>[\\s\\S]*?<\\/style>"; // 定义style的正则表达式 
            string regEx_script = "<script[^>]*?>[\\s\\S]*?<\\/script>"; // 定义 script的正则表达式 
            string regEx_html = "<[^>]+>"; // 定义HTML标签的正则表达式 
            htmlStr = Regex.Replace(htmlStr, regEx_style, string.Empty); // 删除css
            htmlStr = Regex.Replace(htmlStr, regEx_script, string.Empty); // 删除js
            htmlStr = Regex.Replace(htmlStr, regEx_html, string.Empty); // 删除html标记
            ///htmlStr = Regex.Replace(htmlStr, "\\s*|\t|\r|\n", string.Empty);//去除tab、空格、空行
            ///htmlStr = htmlStr.Replace(" ", "");
            ///htmlStr = htmlStr.Replace("\"", "");//去除异常的引号" " "
            ///htmlStr = htmlStr.Replace("\"", "");
            return htmlStr.Trim();
        }

        /// <summary>
        /// 获取顺序GUID字符串
        /// </summary>
        /// <returns></returns>
        public static string GetSequentialGuidId()
        {
            var ps = LibSequentialGuidUtils.Next();
            return ps.ToString();
        }
    }
}
